یاد بگیرید چگونه با استفاده از Route Handler های Next.js نقاط پایانی API قدرتمند ایجاد کنید. این راهنما همه چیز را از راهاندازی اولیه تا تکنیکهای پیشرفته، با مثالهای کاربردی و بهترین شیوهها پوشش میدهد.
Next.js Route Handlers: راهنمای جامع برای ایجاد نقاط پایانی API
Next.js با ویژگیهای قدرتمند خود مانند رندر سمت سرور، تولید سایت استاتیک و اکنون، Route Handlers، شیوه ساخت برنامههای وب را متحول کرده است. Route Handlers روشی انعطافپذیر و کارآمد برای ایجاد نقاط پایانی (endpoints) API مستقیماً در داخل برنامه Next.js شما فراهم میکنند. این راهنما به بررسی مفهوم Route Handlers، مزایای آنها و نحوه استفاده مؤثر از آنها برای ساخت APIهای قوی میپردازد.
Route Handler های Next.js چه هستند؟
Route Handlers توابعی هستند که در دایرکتوری app
یک پروژه Next.js تعریف میشوند و درخواستهای HTTP ورودی را مدیریت میکنند. برخلاف رویکرد قدیمی pages/api
(که از API Routes استفاده میکند)، Route Handlers روشی سادهتر و انعطافپذیرتر برای تعریف نقاط پایانی API در کنار کامپوننتهای React شما ارائه میدهند. آنها اساساً توابع بدون سرور (serverless) هستند که بر روی edge یا محیط سرور انتخابی شما اجرا میشوند.
Route Handlers را به عنوان منطق بکاند برنامه Next.js خود در نظر بگیرید که مسئول پردازش درخواستها، تعامل با پایگاههای داده و بازگرداندن پاسخها هستند.
مزایای استفاده از Route Handlers
- هممکانی (Colocation): Route Handlers مستقیماً در کنار کامپوننتهای React شما در دایرکتوری
app
قرار میگیرند که باعث سازماندهی بهتر و قابلیت نگهداری کد میشود. - پشتیبانی از TypeScript: پشتیبانی داخلی از TypeScript ایمنی نوع (type safety) و تجربه بهتر توسعهدهنده را تضمین میکند.
- ادغام با Middleware: به راحتی میتوانید middleware را برای وظایفی مانند احراز هویت، اعطای دسترسی و اعتبارسنجی درخواستها ادغام کنید.
- پشتیبانی از Streaming: Route Handlers میتوانند دادهها را به صورت جریانی (stream) ارسال کنند، که به شما امکان میدهد پاسخها را به صورت تدریجی ارسال کنید، که برای مجموعه دادههای بزرگ یا فرآیندهای طولانیمدت مفید است.
- توابع Edge: Route Handlers را به عنوان توابع Edge (Edge Functions) برای پاسخهای با تأخیر کم و نزدیکتر به کاربران خود، با بهرهگیری از CDNهای جهانی، مستقر کنید.
- طراحی سادهتر API: Route Handlers یک API تمیز و شهودی برای مدیریت درخواستها و پاسخها فراهم میکنند.
- ادغام با Server Actions: ادغام تنگاتنگ با Server Actions امکان ارتباط یکپارچه بین کامپوننتهای سمت کلاینت و منطق سمت سرور شما را فراهم میکند.
راهاندازی پروژه Next.js شما
قبل از پرداختن به Route Handlers، اطمینان حاصل کنید که یک پروژه Next.js با دایرکتوری app
راهاندازی کردهاید. اگر در حال شروع یک پروژه جدید هستید، از دستور زیر استفاده کنید:
npx create-next-app@latest my-nextjs-app
در طول فرآیند راهاندازی، دایرکتوری app
را انتخاب کنید تا سیستم مسیریابی جدید فعال شود.
ایجاد اولین Route Handler
بیایید یک نقطه پایانی API ساده ایجاد کنیم که یک پاسخ JSON برمیگرداند. یک دایرکتوری جدید در داخل دایرکتوری app
ایجاد کنید، به عنوان مثال، /app/api/hello
. در داخل این دایرکتوری، فایلی به نام route.ts
(یا route.js
اگر از TypeScript استفاده نمیکنید) ایجاد کنید.
در اینجا کد اولین Route Handler شما آمده است:
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'سلام از طرف Route Handlers های Next.js!' });
}
توضیح:
import { NextResponse } from 'next/server';
: آبجکتNextResponse
را وارد میکند که برای ساخت پاسخهای API استفاده میشود.export async function GET(request: Request) { ... }
: یک تابع ناهمزمان تعریف میکند که درخواستهای GET به نقطه پایانی/api/hello
را مدیریت میکند. پارامترrequest
دسترسی به آبجکت درخواست ورودی را فراهم میکند.return NextResponse.json({ message: 'سلام از طرف Route Handlers های Next.js!' });
: یک پاسخ JSON با یک پیام ایجاد کرده و آن را با استفاده ازNextResponse.json()
برمیگرداند.
اکنون، میتوانید با مراجعه به /api/hello
در مرورگر خود یا استفاده از ابزاری مانند curl
یا Postman
به این نقطه پایانی دسترسی پیدا کنید.
مدیریت متدهای مختلف HTTP
Route Handlers از متدهای مختلف HTTP مانند GET، POST، PUT، DELETE، PATCH و OPTIONS پشتیبانی میکنند. شما میتوانید توابع جداگانهای برای هر متد در همان فایل route.ts
تعریف کنید.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// منطقی برای بازیابی همه کاربران از پایگاه داده
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // دادههای نمونه
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // بدنه درخواست را به عنوان JSON تجزیه میکند
// منطقی برای ایجاد یک کاربر جدید در پایگاه داده با استفاده از 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // نمونه
return NextResponse.json(newUser, { status: 201 }); // کاربر جدید را با کد وضعیت 201 Created برمیگرداند
}
توضیح:
- تابع
GET
لیستی از کاربران را (که در اینجا شبیهسازی شده) بازیابی کرده و آنها را به عنوان پاسخ JSON برمیگرداند. - تابع
POST
بدنه درخواست را به عنوان JSON تجزیه میکند، یک کاربر جدید ایجاد میکند (شبیهسازی شده)، و کاربر جدید را با کد وضعیت 201 Created برمیگرداند.
دسترسی به دادههای درخواست
آبجکت request
دسترسی به اطلاعات مختلف در مورد درخواست ورودی، از جمله هدرها، پارامترهای کوئری و بدنه درخواست را فراهم میکند.
هدرها (Headers)
شما میتوانید با استفاده از خاصیت request.headers
به هدرهای درخواست دسترسی پیدا کنید:
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
پارامترهای کوئری (Query Parameters)
برای دسترسی به پارامترهای کوئری، میتوانید از سازنده URL
استفاده کنید:
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
بدنه درخواست (Request Body)
برای درخواستهای POST، PUT و PATCH، میتوانید با استفاده از متدهای request.json()
یا request.text()
، بسته به نوع محتوا، به بدنه درخواست دسترسی پیدا کنید.
export async function POST(request: Request) {
const data = await request.json();
console.log('Data:', data);
return NextResponse.json({ receivedData: data });
}
بازگرداندن پاسخها
آبجکت NextResponse
برای ساخت پاسخهای API استفاده میشود. این آبجکت چندین متد برای تنظیم هدرها، کدهای وضعیت و بدنههای پاسخ فراهم میکند.
پاسخهای JSON
از متد NextResponse.json()
برای بازگرداندن پاسخهای JSON استفاده کنید:
return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });
پاسخهای متنی (Text Responses)
از سازنده new Response()
برای بازگرداندن پاسخهای متنی ساده استفاده کنید:
return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
ریدایرکتها (Redirects)
از NextResponse.redirect()
برای ریدایرکت کردن کاربران به یک URL دیگر استفاده کنید:
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
تنظیم هدرها
شما میتوانید هدرهای سفارشی را با استفاده از گزینه headers
در NextResponse.json()
یا new Response()
تنظیم کنید:
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
ادغام با Middleware
Middleware به شما امکان میدهد کدی را قبل از اینکه درخواست توسط Route Handler شما مدیریت شود، اجرا کنید. این برای احراز هویت، اعطای دسترسی، لاگگیری و سایر نگرانیهای متقاطع (cross-cutting concerns) مفید است.
برای ایجاد یک middleware، فایلی به نام middleware.ts
(یا middleware.js
) در دایرکتوری app
یا هر زیرشاخهای ایجاد کنید. این middleware بر روی تمام مسیرهای داخل آن دایرکتوری و زیرشاخههای آن اعمال خواهد شد.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // این middleware را به مسیرهایی که با /protected/ شروع میشوند اعمال کن
};
توضیح:
- تابع
middleware
وجود یک توکن احراز هویت را در کوکیهای درخواست بررسی میکند. - اگر توکن وجود نداشته باشد، کاربر را به صفحه ورود ریدایرکت میکند.
- در غیر این صورت، به درخواست اجازه میدهد تا به Route Handler ادامه دهد.
- آبجکت
config
مشخص میکند که این middleware فقط باید برای مسیرهایی که با/protected/
شروع میشوند اعمال شود.
مدیریت خطا (Error Handling)
مدیریت صحیح خطا برای ساخت APIهای قوی بسیار مهم است. شما میتوانید از بلوکهای try...catch
برای مدیریت استثناها و بازگرداندن پاسخهای خطای مناسب استفاده کنید.
export async function GET(request: Request) {
try {
// شبیهسازی یک خطا
throw new Error('Something went wrong!');
} catch (error: any) {
console.error('Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
توضیح:
- بلوک
try...catch
هر استثنایی را که در داخل Route Handler رخ دهد، میگیرد. - در بلوک
catch
، خطا لاگ میشود و یک پاسخ خطا با کد وضعیت 500 Internal Server Error بازگردانده میشود.
پاسخهای جریانی (Streaming Responses)
Route Handlers از پاسخهای جریانی پشتیبانی میکنند، که به شما امکان میدهد دادهها را به صورت تدریجی به کلاینت ارسال کنید. این به ویژه برای مجموعه دادههای بزرگ یا فرآیندهای طولانیمدت مفید است.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // شبیهسازی تأخیر
yield `Data chunk ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
توضیح:
- تابع
generateData
یک مولد ناهمزمان است که تکههای داده را با تأخیر تولید (yield) میکند. - متد
Readable.from()
یک جریان خواندنی (readable stream) از مولد ایجاد میکند. - آبجکت
Response
با جریان خواندنی به عنوان بدنه ایجاد میشود و هدرContent-Type
رویtext/plain
تنظیم میشود.
احراز هویت و اعطای دسترسی (Authentication and Authorization)
امن کردن نقاط پایانی API شما بسیار حیاتی است. شما میتوانید احراز هویت و اعطای دسترسی را با استفاده از middleware یا مستقیماً در داخل Route Handlers خود پیادهسازی کنید.
احراز هویت (Authentication)
احراز هویت، هویت کاربری که درخواست را ارسال میکند، تأیید میکند. روشهای رایج احراز هویت عبارتند از:
- JWT (JSON Web Tokens): پس از ورود موفق، یک توکن تولید کنید و آن را در درخواستهای بعدی تأیید کنید.
- احراز هویت مبتنی بر نشست (Session-based Authentication): از کوکیها برای ذخیره شناسههای نشست استفاده کنید و آنها را در هر درخواست تأیید کنید.
- OAuth: احراز هویت را به یک ارائهدهنده شخص ثالث مانند گوگل یا فیسبوک واگذار کنید.
در اینجا یک مثال از احراز هویت JWT با استفاده از middleware آورده شده است:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // با یک کلید مخفی قوی و تصادفی جایگزین کنید
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
اعطای دسترسی (Authorization)
اعطای دسترسی تعیین میکند که یک کاربر به چه منابعی اجازه دسترسی دارد. این معمولاً بر اساس نقشها یا مجوزها است.
شما میتوانید اعطای دسترسی را در داخل Route Handlers خود با بررسی نقشها یا مجوزهای کاربر و بازگرداندن یک خطا در صورت عدم دسترسی، پیادهسازی کنید.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// فرض کنید تابعی برای گرفتن نقش کاربر از توکن یا نشست دارید
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
}
// منطقی برای بازیابی دادههای ادمین
const adminData = { message: 'Admin data' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// با منطق واقعی خود برای استخراج نقش کاربر از درخواست جایگزین کنید
// این میتواند شامل تأیید یک توکن JWT یا بررسی یک نشست باشد
return 'admin'; // مثال: نقش هاردکد شده برای نمایش
}
استقرار (Deploying) Route Handlers
Route Handlers به عنوان توابع بدون سرور (serverless) بر روی ارائهدهنده هاستینگ انتخابی شما مستقر میشوند. Next.js از پلتفرمهای مختلف استقرار، از جمله Vercel، Netlify، AWS و غیره پشتیبانی میکند.
برای Vercel، استقرار به سادگی اتصال مخزن Git شما به Vercel و push کردن کد شماست. Vercel به طور خودکار پروژه Next.js شما را شناسایی کرده و Route Handlers شما را به عنوان توابع بدون سرور مستقر میکند.
تکنیکهای پیشرفته
توابع Edge (Edge Functions)
Route Handlers میتوانند به عنوان توابع Edge مستقر شوند که در لبه یک CDN، نزدیکتر به کاربران شما اجرا میشوند. این میتواند به طور قابل توجهی تأخیر را کاهش داده و عملکرد را بهبود بخشد.
برای استقرار یک Route Handler به عنوان یک تابع Edge، رانتایم edge
را به فایل route.ts
خود اضافه کنید:
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'سلام از Edge!' });
}
اکشنهای سرور (Server Actions)
Server Actions به شما امکان میدهند کد سمت سرور را مستقیماً از کامپوننتهای React خود اجرا کنید. Route Handlers و Server Actions به طور یکپارچه با هم کار میکنند و به شما امکان میدهند برنامههای پیچیده را به راحتی بسازید.
در اینجا مثالی از استفاده از یک Server Action برای فراخوانی یک Route Handler آورده شده است:
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // صفحه را برای اعمال تغییرات رفرش کن
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
کش کردن (Caching)
کش کردن میتواند به طور قابل توجهی عملکرد نقاط پایانی API شما را بهبود بخشد. شما میتوانید از هدر Cache-Control
برای کنترل نحوه کش شدن پاسخهای خود توسط مرورگرها و CDNها استفاده کنید.
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
این مثال هدر Cache-Control
را روی public, max-age=3600
تنظیم میکند، که به مرورگرها و CDNها میگوید که پاسخ را برای یک ساعت کش کنند.
بهترین شیوهها (Best Practices)
- از TypeScript استفاده کنید: از ایمنی نوع TypeScript برای بهبود کیفیت کد و جلوگیری از خطاها بهره ببرید.
- درخواستها را اعتبارسنجی کنید: درخواستهای ورودی را برای اطمینان از یکپارچگی دادهها و جلوگیری از ورودیهای مخرب اعتبارسنجی کنید.
- خطاها را به درستی مدیریت کنید: مدیریت خطای مناسب را برای ارائه پیامهای خطای آموزنده به کلاینتها پیادهسازی کنید.
- نقاط پایانی خود را امن کنید: احراز هویت و اعطای دسترسی را برای محافظت از نقاط پایانی API خود پیادهسازی کنید.
- از Middleware استفاده کنید: از middleware برای نگرانیهای متقاطع مانند احراز هویت، لاگگیری و اعتبارسنجی درخواست استفاده کنید.
- پاسخها را کش کنید: از کش کردن برای بهبود عملکرد نقاط پایانی API خود استفاده کنید.
- APIهای خود را نظارت کنید: APIهای خود را برای شناسایی و حل سریع مشکلات نظارت کنید.
- APIهای خود را مستند کنید: APIهای خود را مستند کنید تا استفاده از آنها برای سایر توسعهدهندگان آسان باشد. استفاده از ابزارهایی مانند Swagger/OpenAPI را برای مستندسازی API در نظر بگیرید.
مثالهای دنیای واقعی
در اینجا چند مثال واقعی از نحوه استفاده از Route Handlers آورده شده است:
- API تجارت الکترونیک: ایجاد نقاط پایانی API برای مدیریت محصولات، سفارشها و کاربران.
- API رسانههای اجتماعی: ایجاد نقاط پایانی API برای ارسال توییت، دنبال کردن کاربران و بازیابی تایملاینها.
- API سیستم مدیریت محتوا (CMS): ایجاد نقاط پایانی API برای مدیریت محتوا، کاربران و تنظیمات.
- API تحلیل داده: ایجاد نقاط پایانی API برای جمعآوری و تحلیل دادهها. به عنوان مثال، یک Route Handler میتواند دادهها را از پیکسلهای ردیابی در وبسایتهای مختلف دریافت کرده و اطلاعات را برای گزارشدهی agregagate کند.
مثال تجارت الکترونیک بینالمللی: یک Route Handler که برای بازیابی قیمتگذاری محصول بر اساس کشور کاربر استفاده میشود. این نقطه پایانی میتواند از موقعیت جغرافیایی درخواست (که از آدرس IP استخراج میشود) برای تعیین موقعیت کاربر و بازگرداندن قیمتها با واحد پول مناسب استفاده کند. این به یک تجربه خرید بومیسازی شده کمک میکند.
مثال احراز هویت جهانی: یک Route Handler که احراز هویت چند عاملی (MFA) را برای کاربران در سراسر جهان پیادهسازی میکند. این میتواند شامل ارسال کدهای SMS یا استفاده از برنامههای احراز هویت باشد، در حالی که به مقررات حریم خصوصی و زیرساختهای مخابراتی مناطق مختلف احترام میگذارد.
تحویل محتوای چند زبانه: یک Route Handler که محتوا را به زبان ترجیحی کاربر تحویل میدهد. این را میتوان از هدر `Accept-Language` در درخواست تعیین کرد. این مثال نیاز به رمزگذاری مناسب UTF-8 و پشتیبانی از زبانهای راست به چپ در صورت لزوم را برجسته میکند.
نتیجهگیری
Route Handlers های Next.js یک راه قدرتمند و انعطافپذیر برای ایجاد نقاط پایانی API مستقیماً در داخل برنامه Next.js شما فراهم میکنند. با بهرهگیری از Route Handlers، میتوانید APIهای قوی را به راحتی بسازید، منطق بکاند خود را با کامپوننتهای React خود هممکان کنید و از ویژگیهایی مانند middleware، streaming و توابع Edge بهرهمند شوید.
این راهنمای جامع همه چیز را از راهاندازی اولیه تا تکنیکهای پیشرفته پوشش داده است. با پیروی از بهترین شیوههای ذکر شده در این راهنما، میتوانید APIهای با کیفیتی بسازید که امن، کارآمد و قابل نگهداری باشند.